package com.yn.club.common.jackson;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.TimeZone;

/**
 * jackson 序列化工具
 *
 * @author YN
 */
@Slf4j
public class JacksonUtil {

    public static final DateTimeFormatter NORM_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(
            "yyyy-MM-dd HH:mm:ss", Locale.getDefault()).withZone(ZoneId.systemDefault());

    private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        OBJECT_MAPPER.setLocale(Locale.CHINA);
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        OBJECT_MAPPER.registerModule(new JavaTimeModule());

        SimpleModule module = new SimpleModule();
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(NORM_DATETIME_FORMATTER));
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(NORM_DATETIME_FORMATTER));
        OBJECT_MAPPER.registerModule(module);

        // 对象的所有字段全部列入
        OBJECT_MAPPER.setSerializationInclusion(Include.NON_NULL);
        // 取消默认转换timestamps形式
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 忽略空Bean转json的错误
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许字段单引号
        OBJECT_MAPPER.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
    }

    /**
     * 对象转json字符串
     *
     * @param obj 对象
     * @return
     */
    public static String toJsonStr(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            if (log.isErrorEnabled()) {
                log.error("Json序列化异常", e);
            }
            return "";
        }
    }

    /**
     * 对象转json字符串,格式美化
     *
     * @param obj 对象
     * @return
     */
    public static String toJsonStrPretty(Object obj) {
        try {
            StringWriter writer = new StringWriter(512);
            JsonGenerator generator = OBJECT_MAPPER.getFactory().createGenerator(writer);
            generator.useDefaultPrettyPrinter();
            OBJECT_MAPPER.writeValue(generator, obj);
            writer.flush();
            return writer.toString();
        } catch (IOException e) {
            if (log.isErrorEnabled()) {
                log.error("Json序列化异常", e);
            }
            return "";
        }
    }

    /**
     * json字符串转对象
     *
     * @param json json字符串
     * @return
     */
    public static <T> T toBean(String json, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            if (log.isErrorEnabled()) {
                log.error("Json反序列化异常", e);
            }
            return null;
        }
    }

    /**
     * json字符串转对象
     *
     * @param json json字符串
     * @return
     */
    public static <T> T toBean(String json, TypeReference<T> typeRef) {
        try {
            return OBJECT_MAPPER.readValue(json, typeRef);
        } catch (JsonProcessingException e) {
            if (log.isErrorEnabled()) {
                log.error("Json反序列化异常", e);
            }
            return null;
        }
    }
}
